VAR ReportMsg: PROCEDURE (msg, p0, p1, p2: ARRAY OF CHAR);
PROCEDURE Clone (s: Store): Store;
PROCEDURE New (type: TypeName): Store;
PROCEDURE GetTypeName (s: Store; VAR type: TypeName);
PROCEDURE Report (msg, p0, p1, p2: ARRAY OF CHAR);
PROCEDURE SameType (s0, s1: Store): BOOLEAN;
END Stores.
Module Stores defines a data type Store, which should be used as base type of all storable extensible objects. When storing an object of an extensible type, it is necessary to store not only its contents but also its particular type. The type is needed to create an object of the correct type when reading the data in again.
A variable of (an extension of) type Store is stored in a file. A store must implement the Internalize procedure which takes a Reader as parameter, and the Externalize procedure which takes a Writer as parameter. Readers and writers are mappers on files. The types Views.View and TextModels.Model are examples of Store extensions.
The contents of a store is stored in a file. When reading the same file by another Oberon configuration, it may occur that not all necessary modules are available in this configuration, i.e. the module which defines the store's type cannot be loaded. Yet reading such an "alien" store does not fail completely. Instead of the correct store type, an "alien" object is generated. Obviously such an alien cannot interpret the data it represents, and therefore cannot provide any special behavior. However, it may be copied and stored into another file, such that its contents on the new file are intact and consistent.
Elements are special stores which belong to a particular domain (-> Domains). The elements of a domain can be externalized and internalized such that pointers among them are reconstructed correctly upon internalization. In particular, alias pointers are handled correctly: if several elements point to another element of the same domain, this element is read in only once, and all the pointers to it are rebuilt. Arbitrary graphs can be handled this way, e.g. cyclic data structures. Links to elements of other domains are prohibited. Pointers to non-element stores yield the same store again upon internalization, but alias pointers are not handled: if several elements (or stores) point to a store, internalization creates one new store per pointer, such that each element gets its own independent instance of the store.
Stores provides a pair of mapper types, which are used as parameters in a store's Internalize and Externalize procedures. These readers/writers use the following external (little endian) format:
BOOLEAN
1 byte (0 = FALSE, 1 = TRUE)
1 byte in the Latin-1 character set (i.e. Unicode page 0; 00X..0FFX)
LONGCHAR
2 byte in the Unicode character set (0000H..0FFFFH)
SHORTINT
1 byte (-128..127)
INTEGER
2 bytes (-32768..32767)
LONGINT
4 bytes (-2147483648..2147483647)
4 bytes IEEE format
LONGREAL
8 bytes IEEE format
4 bytes (least significant bit = element 0)
String
string in the Latin-1 character set, followed by a 00X
Long String
string in the Unicode character set, followed by a 0000H
CONST alienVersion
This value is assigned to a Reader's cause field if Reader.ReadVersion read a version outside of the specified range.
CONST alienComponent
This value can be used as cause parameter to Reader.TurnIntoAlien to indicate that the store itself could be read, but that some store contained in it is an alien. As an example, a view may turn itself into an alien if its model is an alien.
CONST inconsistentVersion
This value is assigned to a Reader's cause field if Reader.ReadVersion read a data block which has an inconsistent length, i.e. not all of its data have been read, or it has been attempted to read beyond the end of the data.
CONST inconsistentType
This value is assigned to a Reader's cause field if Reader.ReadVersion detected a change in the type extension hierarchy of the internalized type.
CONST moduleFileNotFound
This value is assigned to a Reader's cause field if Reader.ReadVersion tried to load a module defining an internalized type, and the codefile for this module couldn't be found.
CONST invalidModuleFile
This value is assigned to a Reader's cause field if Reader.ReadVersion tried to load a module defining an internalized type, and the module couldn't be loaded because it imports another module which cannot be loaded for some reason.
CONST inconsModuleVersion
This value is assigned to a Reader's cause field if Reader.ReadVersion tried to load a module defining an internalized type, and the module couldn't be loaded because its version is inconsistent with some already loaded module.
CONST typeNotFound
This value is assigned to a Reader's cause field if Reader.ReadVersion tried to internalize a non-existing type (the module was found, however).
TYPE LONGCHAR
Type for 2-byte characters in the Unicode character set.
TYPE TypeName
String type for the type name of an object.
TYPE TypePath
Array of type names.
TYPE Store
Interface
Storable extensible data types like Views.View or TextModels.Text are derived from Store.
Stores are allocated by suitable directories, e.g. Views.Directory or TextModels.Directory.
Stores are used as base types for all extensible and persistent objects.
A store may be associated with a domain. Such an association may not be changed anymore.
InitDomain is extended by stores which may contain other stores, to propagate the domain to them.
Super call is mandatory in an InitDomain extension.
Not all stores support domains; for such stores InitDomain can be considered empty, except for the first two of the following precondition checks:
domain(s) = NIL OR domain(s) = d 22
s supports domain
dom(s) = d
PROCEDURE (s: Store) Internalize (VAR rd: Reader)
Reads the contents of s from reader rd. Internalize must read the same (amount of) data as is written by the corresponding Externalize procedure.
Internalize is called internally.
Internalize is extended by various persistent object types, e.g. models, views, and controllers.
Extensions must make a super call first.
PROCEDURE (s: Store) Externalize (VAR wr: Writer)
Write the contents of s to writer wr. Externalize must write the same (amount of) data as is read by the corresponding Internalize procedure.
Externalize ist called internally.
Externalize is extended by various persistent object types, e.g. models, views, and controllers.
Extensions must make a super call first.
TYPE Elem
Interface, Extension
Store readers and writers handle pointers between Elem objects of the same domain such that aliases are handled correctly. This means that elements of a domain can form an arbitrary graph, which can be written and read in again without losing its structure. Element pointers must be written/read using Writer.WriteStore and Reader.ReadStore.
domain-: Domains.Domain
The element's domain, which is initialized by the InitDomain procedure.
TYPE Reader
Reader for Oberon/L values like integers, reals, or sets. A reader contains a Files.File, to which it forwards most operations.
Readers are used in the Store.Internalize procedure.
Readers are not extended.
rider-: Files.Reader
The file rider which links a Reader to a file.
cancelled-: BOOLEAN valid during a Store.Internalize call
Tells whether the currently executing Internalize has been called by ReadVersion or TurnIntoAlien.
readAlien-: BOOLEAN
Tells whether any alien has been read since the last ConnectTo.
Connect the reader to a file. All the following operations require connected readers, i.e. rd.rider # NIL. This precondition is not checked explicitly, however. After connecting, the reader's position is at the beginning of the file. If the same reader should be reused on another file, it must first be closed, by connecting it to NIL.
Reads a store's type, allocates it, and then reads its contents, by calling the store's Internalize procedure. x may also be NIL, or an alien if the store's module cannot be loaded, or if internalization has been cancelled by the Internalize procedure.
If the store is an Elem which has already been read in, a pointer to the same Elem is returned instead of allocating a new one.
empty store on file
x = NIL
non-empty store on file
x # NIL
x IS Alien
x.cause # 0
x.type # ""
x.file # NIL
x.pos >= 0 beginning of store's data
x.len >= 0 length of store's data
alien store contents are on x.file in the range [x.pos .. x.pos + x.len[.
These data include only the store's contents, not its prefix
Read a version byte and return it in version. If version is not in the specified range [min .. max], the store currently being read is turned into an alien, with cause = alienVersion.
Connect the writer to a file. All the following operations require connected writers, i.e. wr.rider # NIL. This precondition is not checked explicitly, however. After connecting, the writer's position is at the end of the file. If the same writer should be reused on another file, it must first be closed, by connecting it to NIL.
PROCEDURE (VAR wr: Writer) WriteString (x: ARRAY OF CHAR)
Writes a 00X-terminated string.
PROCEDURE (VAR wr: Writer) WriteLString (x: ARRAY OF LONGCHAR)
Writes a 0000H-terminated string.
PROCEDURE (VAR wr: Writer) WriteStore (x: Store)
Writes the store's type and then its contents, by calling the store's Externalize procedure. x may also be NIL, or an alien.
wr.rider # NIL 20
all Elem stores must be of the same domain during an externalization 21
PROCEDURE WriteVersion (version: SHORTINT)
Writes a version byte.
version >= 0 20
TYPE Alien, AlienComp, AlienElem, AlienPart, AlienPiece
These auxiliary types are used internally, to handle alien stores.
VAR ReportMsg: PROCEDURE (msg, p0, p1, p2: ARRAY OF CHAR)
Used internally.
PROCEDURE New (type: TypeName): Store
Given the name of a store type in the form "module.record", New returns an object of this type. If the defining module is not yet loaded, New tries to load it. If it cannot be loaded, if there is not enough memory, or if the module doesn't define this type, New returns NIL.
New is called internally.
result = NIL
type not available
result # NIL
type available
result has desired type
PROCEDURE Clone (s: Store): Store
Returns the clone of a store.
Clone allocates a new and uninitialized record with the same dynamic type as s.
s # NIL 20
PROCEDURE GetTypeName (s: Store; VAR type: TypeName)
Returns the name of a store's record type.
PROCEDURE Report (msg, p0, p1, p2: ARRAY OF CHAR)
Used internally.
PROCEDURE SameType (s0, s1: Store): BOOLEAN
Tests whether s0 and s1 both have exactly the same dynamic type.